package com.tomecode.tools.maven.settings.gui.tabs;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import java.util.List;

import javax.swing.AbstractListModel;
import javax.swing.JCheckBox;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.JTextField;
import javax.swing.ListSelectionModel;
import javax.swing.border.EmptyBorder;
import javax.swing.table.AbstractTableModel;

import com.tomecode.tools.maven.settings.gui.Desktop;
import com.tomecode.tools.maven.settings.model.Proxy;
import com.tomecode.tools.maven.settings.model.Settings;
import com.tomecode.util.gui.PanelFactory;
import com.tomecode.util.gui.component.Button;

/**
 * 
 * {@link Proxy} editor
 * 
 * @author Frastia Tomas
 * 
 */
public final class ProxiesTab extends JPanel {

	private static final long serialVersionUID = -4888395834580324620L;
	private final JTable proxyTable;
	private final ProxyTableModel proxyTableModel;

	private final JPanel editorPanel;

	private final JTextField txtId;
	private final JCheckBox checkActive;
	private final JTextField txtProtocol;
	private final JTextField txtHost;
	private final JTextField txtPort;
	private final JTextField txtUsername;
	private final JTextField txtPassword;

	private final Button bDelete;
	private final Button bEdit;
	private final Button bSave;

	private final Button bNonProxySave;
	private final Button bNonProxyEdit;
	private final Button bNonProxyDelete;

	private final JLabel labError;

	private final JList listNonProxyHost;
	private final NonProxyHostListModel listNonProxyHostModel;

	public ProxiesTab(Settings settings) {
		super(new BorderLayout());
		setBorder(new EmptyBorder(10, 10, 0, 10));
		proxyTableModel = new ProxyTableModel(settings);
		proxyTable = new JTable(proxyTableModel);
		listNonProxyHostModel = new NonProxyHostListModel();
		listNonProxyHost = new JList(listNonProxyHostModel);
		listNonProxyHost.addKeyListener(new KeyAdapter() {
			public final void keyReleased(KeyEvent e) {
				stateNonProxyHostEditButt(listNonProxyHost.getSelectedIndex() != -1);
			}

		});

		listNonProxyHost.addMouseListener(new MouseAdapter() {
			public final void mouseClicked(MouseEvent e) {
				stateNonProxyHostEditButt(listNonProxyHost.getSelectedIndex() != -1);
			}
		});

		labError = new JLabel(" ");
		labError.setForeground(Color.red);

		proxyTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
		proxyTable.setAutoscrolls(true);

		bDelete = new Button("Delete", false, new ActionListener() {
			public final void actionPerformed(ActionEvent e) {
				if (proxyTable.getSelectedRow() == -1) {
					return;
				}
				proxyTableModel.remove(proxyTable.getSelectedRow());
				cleanTxts();
			}
		});
		bEdit = new Button("Edit", false, new ActionListener() {
			public final void actionPerformed(ActionEvent e) {
				if (proxyTable.getSelectedRow() == -1) {
					return;
				}
				proxyTableModel.update(proxyTable.getSelectedRow(), txtId.getText(), String.valueOf(checkActive.isSelected()), txtProtocol.getText(), txtHost.getText(), txtPort.getText(), txtUsername.getText(), txtPassword.getText(), listNonProxyHostModel.getHosts());
				cleanTxts();
			}
		});
		bSave = new Button("Save", false, new ActionListener() {
			public final void actionPerformed(ActionEvent e) {
				proxyTableModel.add(txtId.getText(), String.valueOf(checkActive.isSelected()), txtProtocol.getText(), txtHost.getText(), txtPort.getText(), txtUsername.getText(), txtPassword.getText(), listNonProxyHostModel.getHosts());
				cleanTxts();
			}
		});

		add(new JScrollPane(proxyTable), BorderLayout.CENTER);

		txtId = new JTextField();
		txtId.addKeyListener(new KeyAdapter() {
			public final void keyReleased(KeyEvent e) {
				if (checkIfProxyExists()) {
					validatePort();
				}
			}
		});
		checkActive = new JCheckBox();
		txtProtocol = new JTextField();
		txtHost = new JTextField();
		txtPort = new JTextField();
		txtPort.addKeyListener(new KeyAdapter() {
			public final void keyReleased(KeyEvent e) {
				if (validatePort()) {
					checkIfProxyExists();
				}
			}
		});
		txtUsername = new JTextField();
		txtPassword = new JTextField();

		editorPanel = PanelFactory.createBorderLayout("Server");
		JPanel pFields = PanelFactory.createGridLayout(7, 1);
		editorPanel.add(pFields, BorderLayout.CENTER);
		pFields.add(PanelFactory.wrapWithLabelNorm("Id:", txtId, 94));
		pFields.add(PanelFactory.wrapWithLabelNorm("Protocol:", txtProtocol, 56));
		pFields.add(PanelFactory.wrapWithLabelNorm("Host:", txtHost, 78));
		pFields.add(PanelFactory.wrapWithLabelNorm("Port:", txtPort, 80));
		pFields.add(PanelFactory.wrapWithLabelNorm("Username:", txtUsername, 45));
		pFields.add(PanelFactory.wrapWithLabelNorm("Password:", txtPassword, 46));

		bNonProxySave = new Button("Add", true, new ActionListener() {
			public final void actionPerformed(ActionEvent e) {
				String s = (String) JOptionPane.showInputDialog(Desktop.getComponent(), "Non Proxy Hosts:", "New - Non Proxy Hosts", JOptionPane.PLAIN_MESSAGE);
				if (s != null && s.trim().length() != 0) {
					listNonProxyHostModel.add(s);
				}
				listNonProxyHost.updateUI();
			}
		});

		bNonProxyEdit = new Button("Edit", false, new ActionListener() {
			public final void actionPerformed(ActionEvent e) {
				if (listNonProxyHost.getSelectedIndex() == -1) {
					return;
				}
				String s = (String) JOptionPane.showInputDialog(Desktop.getComponent(), "Edit '" + listNonProxyHostModel.get(listNonProxyHost.getSelectedIndex()) + "' Non Proxy Hosts:", "Edit - Non Proxy Hosts", JOptionPane.PLAIN_MESSAGE);
				if (s != null && s.trim().length() != 0) {
					listNonProxyHostModel.edit(listNonProxyHost.getSelectedIndex(), s);
				}
				listNonProxyHost.updateUI();
				stateNonProxyHostEditButt(false);
			}
		});
		bNonProxyDelete = new Button("Del", false, new ActionListener() {
			public final void actionPerformed(ActionEvent e) {
				if (listNonProxyHost.getSelectedIndex() == -1) {
					return;
				}
				int n = JOptionPane.showOptionDialog(Desktop.getComponent(), "Delete '" + listNonProxyHostModel.get(listNonProxyHost.getSelectedIndex()) + "' Non Proxy Hosts", "Delete - Non Proxy Hosts", JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE, null, null, null);
				if (n == JOptionPane.YES_OPTION) {
					listNonProxyHostModel.remove(listNonProxyHost.getSelectedIndex());
				}
				listNonProxyHost.updateUI();
				stateNonProxyHostEditButt(false);
			}
		});

		// pFields.add(PanelFactory.wrapWithLabelNorm("Non Proxy Hosts:",
		// txtNonProxyHosts, 10));
		pFields.add(PanelFactory.wrapWithLabelNorm("Active:", checkActive, 65));
		// pFields.add(pNonProxyHost);

		JPanel pNonProxyHostButt = PanelFactory.createGridLayout(3, 1);
		pNonProxyHostButt.add(bNonProxySave);
		pNonProxyHostButt.add(bNonProxyEdit);
		pNonProxyHostButt.add(bNonProxyDelete);

		JPanel pNonProxyHost = PanelFactory.createBorderLayout("Non Proxy Hosts");
		pNonProxyHost.add(new JScrollPane(listNonProxyHost), BorderLayout.CENTER);
		pNonProxyHost.add(PanelFactory.wrapByBorderLayout(pNonProxyHostButt, BorderLayout.NORTH), BorderLayout.EAST);
		JPanel pSouth = PanelFactory.createBorderLayout(0, 0, 0, 0);
		pSouth.add(pNonProxyHost, BorderLayout.NORTH);
		JPanel pSouthButtons = PanelFactory.createBorderLayout(0, 0, 0, 0);
		pSouthButtons.add(PanelFactory.createButtonsPanel(0, 0, 0, -4, bSave, bEdit, bDelete), BorderLayout.EAST);
		pSouthButtons.add(labError, BorderLayout.CENTER);
		pSouth.add(pSouthButtons, BorderLayout.SOUTH);
		editorPanel.add(pSouth, BorderLayout.SOUTH);

		add(editorPanel, BorderLayout.SOUTH);

		proxyTable.addKeyListener(new KeyAdapter() {
			public final void keyReleased(KeyEvent e) {
				selectInTable(proxyTable.getSelectedRow());
			}

		});

		proxyTable.addMouseListener(new MouseAdapter() {
			public final void mouseClicked(MouseEvent e) {
				selectInTable(proxyTable.getSelectedRow());
			}
		});

	}

	/**
	 * enable or disable head buttons
	 * 
	 * @param state
	 */
	private final void stateNonProxyHostEditButt(boolean state) {
		bNonProxyDelete.setEnabled(state);
		bNonProxyEdit.setEnabled(state);
	}

	private final boolean validatePort() {
		if (txtPort.getText().trim().length() == 0) {
			return true;
		}
		try {
			Integer.parseInt(txtPort.getText());
			bEdit.setEnabled(proxyTable.getSelectedRow() != -1);
			bSave.setEnabled(true);
			labError.setText(" ");
			return true;
		} catch (NumberFormatException ex) {
			bEdit.setEnabled(false);
			bSave.setEnabled(false);
			labError.setText("Proxy port is not number");
		}
		return false;
	}

	private final boolean checkIfProxyExists() {
		if (txtId.getText().trim().length() == 0) {
			labError.setText("Proxy id cannot be empty");
			bSave.setEnabled(false);
			bEdit.setEnabled(false);
			return false;
		} else if (proxyTableModel.exists(txtId.getText())) {
			labError.setText("Proxy id already exists");
			bSave.setEnabled(false);
			return false;
		} else {
			labError.setText(" ");
			bSave.setEnabled(true);
			bEdit.setEnabled(proxyTable.getSelectedRow() != -1);
		}
		return true;
	}

	private final void selectInTable(int selectedRow) {
		if (selectedRow == -1) {
			cleanTxts();
			return;
		}
		Proxy proxy = proxyTableModel.get(selectedRow);
		txtId.setText(proxy.getId());
		txtPassword.setText(proxy.getPassword());
		txtUsername.setText(proxy.getUsername());
		txtPort.setText(proxy.getPort());
		txtProtocol.setText(proxy.getProtocol());
		txtHost.setText(proxy.getHost());
		checkActive.setSelected(proxy.isActive());

		listNonProxyHostModel.addAll(proxy.getNonProxyHosts());
		listNonProxyHost.updateUI();

		bDelete.setEnabled(true);
		bEdit.setEnabled(true);
		bSave.setEnabled(true);
		if (checkIfProxyExists()) {
			validatePort();
		}
	}

	private final void cleanTxts() {
		txtId.setText("");
		txtPassword.setText("");
		txtUsername.setText("");
		txtPort.setText("");
		txtProtocol.setText("");
		txtHost.setText("");
		checkActive.setSelected(false);
		bDelete.setEnabled(false);
		bEdit.setEnabled(false);
		bSave.setEnabled(false);
		labError.setText(" ");
		listNonProxyHostModel.clean();
		listNonProxyHost.updateUI();
		stateNonProxyHostEditButt(false);
	}

	/**
	 * non proxy host data model
	 * 
	 * @author Frastia Tomas
	 * 
	 */
	private final class NonProxyHostListModel extends AbstractListModel {

		private static final long serialVersionUID = -1448028316041145568L;

		private final List<String> data;

		private NonProxyHostListModel() {
			data = new ArrayList<String>();
		}

		private final void addAll(List<String> nonProxyHosts) {
			data.clear();
			data.addAll(nonProxyHosts);
		}

		private final void clean() {
			data.clear();
		}

		private final String get(int selectedIndex) {
			return data.get(selectedIndex);
		}

		public final String getElementAt(int index) {
			return data.get(index);
		}

		public final void add(String host) {
			data.add(host);
		}

		public final void remove(int index) {
			data.remove(index);
		}

		public final void edit(int index, String host) {
			data.set(index, host);
		}

		public final int getSize() {
			return data.size();
		}

		private final List<String> getHosts() {
			return data;
		}

	}

	/**
	 * Proxy table model
	 * 
	 * @author Frastia Tomas
	 * 
	 */
	private final class ProxyTableModel extends AbstractTableModel {

		private static final long serialVersionUID = 3479286243525778842L;

		private final String[] columns = new String[] { "Id", "Host", "User", "Active" };

		private final Settings settings;

		private ProxyTableModel(Settings settings) {
			this.settings = settings;
		}

		public final Class<?> getColumnClass(int columnIndex) {
			return (columnIndex == 3 ? Boolean.class : String.class);
		}

		public final boolean isCellEditable(int rowIndex, int columnIndex) {
			return (columnIndex == 3);
		}

		private final boolean exists(String id) {
			return settings.existsProxy(id);
		}

		private final Proxy get(int selectedRow) {
			return settings.getProxies().get(selectedRow);
		}

		private final void add(String id, String active, String protocol, String host, String port, String username, String password, List<String> nonProxyHosts) {
			Proxy proxy = new Proxy();
			proxy.setId(id);
			proxy.setActive(active);
			proxy.setProtocol(protocol);
			proxy.setHost(host);
			proxy.setPort(port);
			proxy.setUsername(username);
			proxy.setPassword(password);
			proxy.setNonProxyHosts(nonProxyHosts);
			settings.addProxy(proxy);
			fireTableDataChanged();
			fireTableStructureChanged();
		}

		private final void update(int selectedRow, String id, String active, String protocol, String host, String port, String username, String password, List<String> nonProxyHosts) {
			Proxy proxy = settings.getProxies().get(selectedRow);
			proxy.setId(id);
			proxy.setActive(active);
			proxy.setProtocol(protocol);
			proxy.setHost(host);
			proxy.setPort(port);
			proxy.setUsername(username);
			proxy.setPassword(password);
			proxy.setNonProxyHosts(nonProxyHosts);
			fireTableDataChanged();
		}

		private final void remove(int selectedRow) {
			settings.getProxies().remove(selectedRow);
			fireTableDataChanged();
		}

		public final int getColumnCount() {
			return columns.length;
		}

		public final int getRowCount() {
			return this.settings.getProxies().size();
		}

		public final String getColumnName(int column) {
			return columns[column];
		}

		public final Object getValueAt(int rowIndex, int columnIndex) {
			Proxy proxy = this.settings.getProxies().get(rowIndex);
			if (columnIndex == 0) {
				return proxy.getId();
			} else if (columnIndex == 1) {
				return proxy.getHost();
			} else if (columnIndex == 2) {
				return proxy.getUsername();
			} else if (columnIndex == 3) {
				return proxy.isActive();
			}
			return null;
		}

		public final void setValueAt(Object aValue, int rowIndex, int columnIndex) {
			Proxy proxy = this.settings.getProxies().get(rowIndex);
			proxy.setActive(aValue.toString());
		}

	}
}
